﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BitmapToAscii
{
    public partial class Form1 : Form
    {
        string Title;
        decimal prevState = 0;

        bool inEvent = false;

        public Form1()
        {
            InitializeComponent();
        }

        #region FormEvents

        private void txbFile_TextChanged(object sender, EventArgs e)
        {
            if (!File.Exists(txbFile.Text))
                return;

            LoadPic(txbFile.Text);
        }

        private void btnFileOpenDialog_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.ShowDialog();

            if (!string.IsNullOrEmpty(dlg.FileName))
                txbFile.Text = dlg.FileName;
        }

        private void numPixelsPerChar_ValueChanged(object sender, EventArgs e)
        {
            if (inEvent)
                return;

            try
            {
                inEvent = true;

                bool up = numPixelsPerChar.Value > prevState;

                // preveri vsebino txbRatio in jo popravi tako, da je stevilo poplni koren
                double val = (double)numPixelsPerChar.Value;
                double valSqrt = Math.Sqrt(val);
                val = Math.Ceiling(Math.Pow(up ? Math.Ceiling(valSqrt) : Math.Floor(valSqrt), 2));

                bool changed = (decimal)val != numPixelsPerChar.Value;
                
                numPixelsPerChar.Value = (decimal)val;

                if (changed && !string.IsNullOrWhiteSpace(txbFile.Text))
                    PicToAscii((Bitmap)Picture.Image);

                prevState = numPixelsPerChar.Value;
            }
            finally
            {
                inEvent = false;
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(ASCII.Text))
                return;

            using (SaveFileDialog dlg = new SaveFileDialog())
            {
                dlg.Filter = "Text files|*.txt";
                dlg.AddExtension = true;
                dlg.FileName = Title;
                dlg.ShowDialog();

                using (StreamWriter writter = new StreamWriter(File.Create(dlg.FileName)))
                {
                    writter.Write(ASCII.Text);
                }
            }
        }

        #endregion

        string getFileName(string FilePath)
        {
            char[] filename = new char[FilePath.Length];
            int index = 0;

            bool ZadnjaPika = false;
            for (int i = FilePath.Length - 1; i >= 0; i--)
            {
                if (FilePath[i] == '\\')
                    break;

                if (ZadnjaPika)
                {
                    for (int j = index++; j >= 0; j--)
                        filename[j + 1] = filename[j];
                    filename[0] = FilePath[i];
                }

                if (FilePath[i] == '.') 
                    ZadnjaPika = true;
            }
            return new string(filename, 0, index);
        }

        void LoadPic(string filePath)
        {
            //Odpremo sliko.
            Bitmap bitmap;
            Title = getFileName(filePath);

            try
            {
                bitmap = new Bitmap(Image.FromFile(filePath));
            }
            catch
            {
                //File not an image;
                return;
            }

            Picture.Image = bitmap;
            PicToAscii(bitmap);
        }

        void PicToAscii(Bitmap bitmap)
        {
            string text = string.Empty;

            Color[,] cArray = new Color[bitmap.Height,bitmap.Width];

            for (int i = 0; i < bitmap.Height; i++)
                for (int j = 0; j < bitmap.Width; j++)
                {
                    cArray[i, j] = bitmap.GetPixel(j, i);
                }

            
            int jump = (int)Math.Sqrt((double)numPixelsPerChar.Value); // zagotovo parsa, ker ustrezen event poskrbi za pravi format

            for (int i = 0; i < bitmap.Height-jump; i += jump)
            {
                string line = string.Empty;
                for (int j = 0; j < bitmap.Width-jump; j += jump)
                {
                    Color[,] cRegion = new Color[jump,jump];
                    for(int iRegion = 0; iRegion < jump; iRegion++)
                        for (int jRegion = 0; jRegion < jump; jRegion++)
                        {
                            cRegion[iRegion,jRegion] = cArray[i+iRegion,j+jRegion];
                        }
                    line += ColorToAscii(cRegion);
                }
                text += line + Environment.NewLine;
            }

            ASCII.Text = text;

        }

        enum Barva { White, Black }

        char ColorToAscii(Color[,] cArray)
        {

            #region multipleColorsIntoOne

            Color result;
            byte aa = (byte)255;
            int rr = 0;
            int gg = 0;
            int bb = 0;

            for (int i = 0; i < cArray.GetLength(0); i++)
                for (int j = 0; j < cArray.GetLength(1); j++ )
                {
                    Byte[] components = new Byte[4];
                    components = BitConverter.GetBytes(cArray[i, j].ToArgb());
                    rr += components[1];
                    gg += components[2];
                    bb += components[3];
                }

            int avr = cArray.Length;         // st. elementov v vseh dimenzijah
            rr /= avr;
            gg /= avr;
            bb /= avr;

            byte[] resultByteArray = new byte[4];
            resultByteArray[0] = aa;
            resultByteArray[1] = (byte)rr;
            resultByteArray[2] = (byte)gg;
            resultByteArray[3] = (byte)bb;

            int resultInt = BitConverter.ToInt32(resultByteArray,0);

            result = Color.FromArgb(resultInt);

            Color c = result;       // da Božjakove kode ki sledi ne spreminjam

            #endregion

            Barva b = Barva.White;
            int razdalija = int.MaxValue;

            int r = Math.Abs(Color.White.ToArgb() - c.ToArgb());
            if (r < razdalija)
            {
                b = Barva.White;
                razdalija = r;
            }

            r = Math.Abs(Color.Black.ToArgb() - c.ToArgb());
            if (r < razdalija)
            {
                b = Barva.Black;
                razdalija = r;
            }

            switch (b)
            {
                case Barva.White:
                    return '.';
                case Barva.Black:
                    return '#';
                default:
                    return ' ';
            }
        }
    }
}
